#include <mysql/mysql.h>
#include <malloc.h>

#include "log.h"
#include "mysql_ops.h"
#include "db_ops.h"

static int mysql_ops_query(struct db_ops *this, char *command);
static unsigned int mysql_ops_errorno(struct db_ops *this);
static const char *mysql_ops_error(struct db_ops *this);
static int mysql_ops_sql_server_gone_away(struct db_ops *this, unsigned int errno);

#define SERVER_GONE_AWAY_MYSQL_NO 2006

struct db_ops *get_mysql_ops(char *db_name, char *user_name, char *passwd, char *address)
{
	log_info("begin get_mysql_ops.");

	if (db_name == NULL || user_name == NULL
			|| passwd == NULL || address == NULL) {
		log_error("args is NULL.");
		return NULL;
	}

	struct db_ops *db_ops = (struct db_ops *)malloc(sizeof(struct db_ops)); 
	if (db_ops == NULL) {
		log_error("no enough mem.");
		return NULL;
	}
	
	db_ops->sql_handle = (void *)malloc(sizeof(MYSQL));
	if (db_ops->sql_handle == NULL) {
		log_error("no enough mem.");
		free(db_ops);
		return NULL;
	}

	mysql_init((MYSQL *)(db_ops->sql_handle));

	if (mysql_real_connect((MYSQL *)(db_ops->sql_handle), address, user_name, passwd, db_name, 0, NULL, 0) == 0) {
		log_error("cann't connect to mysql.");
		log_print("cann't connect to mysql.");
		free(db_ops->sql_handle);
		free(db_ops);
		return NULL;
	}

	db_ops->sql_query = mysql_ops_query;
	db_ops->sql_errorno = mysql_ops_errorno;
	db_ops->sql_error = mysql_ops_error;
	db_ops->sql_server_gone_away = mysql_ops_sql_server_gone_away;
	
	return db_ops;
}

static int mysql_ops_query(struct db_ops *this, char *command)
{
	log_info("begin mysql_ops_query.");
	if (this == NULL || command == NULL) {
		log_error("args is NULL.");
		return -1;
	}

	MYSQL *handle = (MYSQL *)(this->sql_handle);
	int res;
	res = mysql_query(handle, command);

	return res;
}

static unsigned int mysql_ops_errorno(struct db_ops *this)
{
	log_info("begin mysql_ops_errorno.");	
	if (this == NULL) {
		log_error("arg is NULL.");
		return 65535;
	}

	MYSQL *handle = (MYSQL *)(this->sql_handle);

	return mysql_errno(handle); 
}

static const char *mysql_ops_error(struct db_ops *this)
{
	log_info("begin mysql_ops_error.");
	if (this == NULL) {
		log_error("arg is NULL.");
		return "<null>";
	}

	MYSQL *handle = (MYSQL *)(this->sql_handle);
	
	return mysql_error(handle);
}

static int mysql_ops_sql_server_gone_away(struct db_ops *this, unsigned int errno)
{
	log_info("begin mysql_ops_sql_server_gone_away.");

	/* We don't need to check if "this" is NULL. */
	
	if (errno == SERVER_GONE_AWAY_MYSQL_NO) {
		return 1;
	}

	return 0;
}
